package com.sunday.common.http.apache.async;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.ContentType;
import org.springframework.lang.Nullable;

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.Future;

/**
 * 异步httpClient连接池工具类
 *
 * @author zsy
 * @since 2024/1/18
 */
@Slf4j
public class AsyncHttpClientPoolUtils {

    private static final CloseableHttpAsyncClient CLOSEABLE_HTTP_ASYNC_CLIENT = AsyncHttpClientPoolBuilder.create().httpAsyncClient();


    public static Future<SimpleHttpResponse> doGet(String url, FutureCallback<SimpleHttpResponse> callback) {
        return doGet(url, callback, null, null, null);
    }

    public static Future<SimpleHttpResponse> doGet(String url, FutureCallback<SimpleHttpResponse> callback, @Nullable CloseableHttpAsyncClient httpAsyncClient) {
        return doGet(url, callback, httpAsyncClient, null, null);
    }

    public static Future<SimpleHttpResponse> doGet(String url, FutureCallback<SimpleHttpResponse> callback, @Nullable Map<String, String> params) {
        return doGet(url, callback, null, null, params);
    }

    public static Future<SimpleHttpResponse> doGet(String url, FutureCallback<SimpleHttpResponse> callback, @Nullable Map<String, String> headers, @Nullable Map<String, String> params) {
        return doGet(url, callback, null, headers, params);
    }

    /**
     * Get 请求
     *
     * @param url
     * @param callback
     * @param httpAsyncClient
     * @param headers
     * @param params
     * @return {@link Future< SimpleHttpResponse>}
     */
    public static Future<SimpleHttpResponse> doGet(String url, FutureCallback<SimpleHttpResponse> callback, @Nullable CloseableHttpAsyncClient httpAsyncClient, @Nullable Map<String, String> headers, @Nullable Map<String, String> params) {
        assert StringUtils.isNotBlank(url) : "url must not be empty";
        assert callback != null : "callback must not be null";
        // 创建HTTP对象
        SimpleRequestBuilder simpleRequestBuilder = SimpleRequestBuilder.get(url);
        // 设置请求头
        setHeader(simpleRequestBuilder, headers);
        // 封装请求参数
        if (ObjectUtils.isNotEmpty(params)) {
            params.forEach((k, v) -> simpleRequestBuilder.addParameter(k, v));
        }
        // 进行了get方法的适配 org.apache.hc.client5.http.async.methods.SimpleRequestBuilder.build
        return getHttpClientResult(simpleRequestBuilder.build(), callback, httpAsyncClient);
    }

    public static Future<SimpleHttpResponse> doPost(String url, FutureCallback<SimpleHttpResponse> callback, @Nullable String json) {
        return doPost(url, callback, null, null, json);
    }

    public static Future<SimpleHttpResponse> doPost(String url, FutureCallback<SimpleHttpResponse> callback, @Nullable CloseableHttpAsyncClient httpAsyncClient, @Nullable String json) {
        return doPost(url, callback, httpAsyncClient, null, json);
    }

    public static Future<SimpleHttpResponse> doPost(String url, FutureCallback<SimpleHttpResponse> callback, @Nullable Map<String, String> headers, @Nullable String json) {
        return doPost(url, callback, null, headers, json);
    }

    /**
     * POST json格式
     *
     * @param url
     * @param callback
     * @param httpAsyncClient
     * @param headers
     * @param json
     * @return {@link Future< SimpleHttpResponse>}
     */
    public static Future<SimpleHttpResponse> doPost(String url, FutureCallback<SimpleHttpResponse> callback, @Nullable CloseableHttpAsyncClient httpAsyncClient, @Nullable Map<String, String> headers, @Nullable String json) {
        assert StringUtils.isNotBlank(url) : "url must not be empty";
        assert callback != null : "callback must not be null";
        // 创建HTTP对象
        SimpleRequestBuilder simpleRequestBuilder = SimpleRequestBuilder.post(url);
        // 设置请求头
        setHeader(simpleRequestBuilder, headers);
        // 封装请求参数
        if (StringUtils.isNotBlank(json)) {
            simpleRequestBuilder.setBody(json, ContentType.APPLICATION_JSON);
        }
        return getHttpClientResult(simpleRequestBuilder.build(), callback, httpAsyncClient);
    }

    public static Future<SimpleHttpResponse> doPost(String url, FutureCallback<SimpleHttpResponse> callback, @Nullable Map<String, String> params) {
        return doPost(url, callback, null, null, params);
    }

    public static Future<SimpleHttpResponse> doPost(String url, FutureCallback<SimpleHttpResponse> callback, @Nullable CloseableHttpAsyncClient httpAsyncClient, @Nullable Map<String, String> params) {
        return doPost(url, callback, httpAsyncClient, null, params);
    }

    public static Future<SimpleHttpResponse> doPost(String url, FutureCallback<SimpleHttpResponse> callback, @Nullable Map<String, String> headers, @Nullable Map<String, String> params) {
        return doPost(url, callback, null, headers, params);
    }

    /**
     * POST Map格式
     *
     * @param url
     * @param callback
     * @param httpAsyncClient
     * @param headers
     * @param params
     * @return {@link Future< SimpleHttpResponse>}
     */
    public static Future<SimpleHttpResponse> doPost(String url, FutureCallback<SimpleHttpResponse> callback, @Nullable CloseableHttpAsyncClient httpAsyncClient, @Nullable Map<String, String> headers, @Nullable Map<String, String> params) {
        assert StringUtils.isNotBlank(url) : "url must not be empty";
        assert callback != null : "callback must not be null";
        // 创建HTTP对象
        SimpleRequestBuilder simpleRequestBuilder = SimpleRequestBuilder.post(url);
        // 设置请求头
        setHeader(simpleRequestBuilder, headers);
        // 封装请求参数
        if (ObjectUtils.isNotEmpty(params)) {
            simpleRequestBuilder.setCharset(StandardCharsets.UTF_8);
            params.forEach((k, v) -> simpleRequestBuilder.addParameter(k, v));
        }
        return getHttpClientResult(simpleRequestBuilder.build(), callback, httpAsyncClient);
    }

    /**
     * 设置封装请求头
     *
     * @param simpleRequestBuilder
     * @param headers
     */
    public static void setHeader(SimpleRequestBuilder simpleRequestBuilder, Map<String, String> headers) {
        if (ObjectUtils.isNotEmpty(headers)) {
            // 设置到请求头到HttpRequestBase对象中
            headers.forEach((k, v) -> simpleRequestBuilder.setHeader(k, v));
        }
    }

    /**
     * 获得响应结果
     *
     * @param request
     * @param callback
     * @param httpAsyncClient
     * @return {@link Future< SimpleHttpResponse>}
     */
    public static Future<SimpleHttpResponse> getHttpClientResult(SimpleHttpRequest request, FutureCallback<SimpleHttpResponse> callback, @Nullable CloseableHttpAsyncClient httpAsyncClient) {
        // 本类默认实现连接池,所以不进行数据源的关闭
        CloseableHttpAsyncClient closeableHttpAsyncClient = httpAsyncClient == null ? CLOSEABLE_HTTP_ASYNC_CLIENT : httpAsyncClient;
        // 执行请求 FutureCallback<SimpleHttpResponse> callback;
        return closeableHttpAsyncClient.execute(request, callback);
    }


}